package com.bjesc_b2c.app.appraiset.camera;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.Camera;
import android.media.AudioManager;
import android.media.ToneGenerator;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.widget.Toast;

import com.bjesc_b2c.app.appraiset.utils.BitmapUtil;
import com.orhanobut.logger.Logger;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

/**
 * 照相机处理类
 * <p>
 * Created by up_girl on 2017/3/30.
 */
public class CameraInterface {
    private static final int MIN_PREVIEW_PIXELS = 480 * 320; // normal screen
    private static final double MAX_ASPECT_DISTORTION = 0.15;
    private static final String TAG = "CameraInterface";
    private Context mContext;
    public Camera mCamera;
    private Camera.Parameters mParams;
    private int mCameraCount;
    private static CameraInterface mCameraInterface;
    private int degrees = 0;
    private int result;
    private ToneGenerator tone;

    public interface CamOpenOverCallback {
        void cameraHasOpened();
    }

    private CameraInterface() {

    }

    public static synchronized CameraInterface getInstance() {

        if (mCameraInterface == null) {
            mCameraInterface = new CameraInterface();
        }
        return mCameraInterface;
    }

    /**
     * 打开Camera前置摄像头
     *
     * @param callback
     */
    public void doOpenCamera(CamOpenOverCallback callback) {
        Log.i(TAG, "Camera open....");
        mCamera = null;
        try {
            Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
            mCameraCount = Camera.getNumberOfCameras(); // get cameras number
            for (int camIdx = 0; camIdx < mCameraCount; camIdx++) {
                Camera.getCameraInfo(camIdx, cameraInfo); // get camerainfo
                if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                    // 代表摄像头的方位，目前有定义值两个分别为CAMERA_FACING_FRONT前置和CAMERA_FACING_BACK后置
                    mCamera = Camera.open(camIdx);
                }
            }
        } catch (Exception e) {
            Log.e(TAG, "报异常，摄像头未正常打开" + e);
        }
        Log.i(TAG, "Camera open over....");
        callback.cameraHasOpened();
    }

    public void setCameraDisplayOrientation(Activity activity,
                                            int cameraId, Camera camera) {
        Camera.CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(cameraId, info);
        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
        Logger.d("rotation==" + rotation);
//        int degrees = 0;
        switch (rotation) {
            case Surface.ROTATION_0:
                degrees = 0;
                break;
            case Surface.ROTATION_90:
                degrees = 90;
                break;
            case Surface.ROTATION_180:
                degrees = 180;
                break;
            case Surface.ROTATION_270:
                degrees = 270;
                break;
        }
//        int result;
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            result = (info.orientation + degrees) % 360;
            result = (360 - result) % 360;  // compensate the mirror
        } else {  // back-facing
            result = (info.orientation - degrees + 360) % 360;
        }
        camera.setDisplayOrientation(result);
    }

    /**
     * 点击区域聚焦
     *
     * @param point
     */
    public void onFocus(Point point) {
        if (mParams != null) {

            //不支持设置自定义聚焦，则使用自动聚焦，返回
            if (mParams.getMaxNumFocusAreas() <= 0) {
                return;
            }
            List<Camera.Area> areas = new ArrayList<Camera.Area>();
            int left = point.x - 300;
            int top = point.y - 300;
            int right = point.x + 300;
            int bottom = point.y + 300;
            left = left < -1000 ? -1000 : left;
            top = top < -1000 ? -1000 : top;
            right = right > 1000 ? 1000 : right;
            bottom = bottom > 1000 ? 1000 : bottom;
            areas.add(new Camera.Area(new Rect(left, top, right, bottom), 100));
            mParams.setFocusAreas(areas);
            try {
                mCamera.setParameters(mParams);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 开启预览
     *
     * @param holder
     * @param width
     */
    public void doStartPreview(Activity activity, SurfaceHolder holder, int width, int height) throws Exception {
        Log.i(TAG, "doStartPreview...");
        mContext = activity;
        if (mCamera != null) {
            try {
                setCameraDisplayOrientation(activity, Camera.CameraInfo.CAMERA_FACING_BACK, mCamera);
                mParams = mCamera.getParameters();
                if (isSupportZoom()) {
                    mParams.setZoom(1);
                }
                mParams.setPictureFormat(PixelFormat.JPEG);//设置拍照后存储的图片格式);
                mParams.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
                Point pointSurfaceView = new Point();
                pointSurfaceView.set(width, height);//获取预览界面在屏幕中的大小
                Point point = findBestPreviewResolution(mParams, pointSurfaceView, degrees, result);
                // 设置PreviewSize和PictureSize
//                Camera.Size previewSize = MyParaUtil.getInstance().getPropPreviewSize(
//                        activity, mParams.getSupportedPreviewSizes(), previwRate, width);
//                Log.i(TAG, "width =" + previewSize.height + ", height =" + previewSize.width);
//                Camera.Size pictureSize = MyParaUtil.getInstance().getPropPictureSize(
//                        mParams.getSupportedPictureSizes(), previewSize.width, previewSize.height);
                Camera.Size pictureSize = MyParaUtil.getInstance().getPropPictureSize(
                        mParams.getSupportedPictureSizes(), point.x, point.y);
//                mParams.setPreviewSize(previewSize.width, previewSize.height);
//                mParams.setPreviewSize(1440, 1080);
                mParams.setPreviewSize(point.x, point.y);
                mParams.setPictureSize(pictureSize.width, pictureSize.height);
                MyParaUtil.getInstance().printSupportFocusMode(mParams);
                List<String> focusModes = mParams.getSupportedFocusModes();
                if (focusModes.contains("continuous-video")) {
                    mParams.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
                }
                mParams.setJpegQuality(100); // 设置照片质量
                mCamera.setParameters(mParams);
                mCamera.setPreviewDisplay(holder);
                mCamera.startPreview();//开启预览
                mParams = mCamera.getParameters(); //重新get一次
                Log.i(TAG, "最终设置1:PreviewSize--With = " + mParams.getPreviewSize().width
                        + "Height = " + mParams.getPreviewSize().height);
                Log.i(TAG, "最终设置2:PictureSize--With = " + mParams.getPictureSize().width
                        + "Height = " + mParams.getPictureSize().height);
            } catch (Exception e) {
                e.printStackTrace();
                Toast.makeText(activity, "预览失败，请重试", Toast.LENGTH_LONG).show();
            }
        }
    }

    public int getPictureWidth() throws Exception {
        return mParams.getPictureSize().width;
    }

    public int getPictureHeight() throws Exception {
        return mParams.getPictureSize().height;
    }

    /**
     * 停止预览，不需要释放Camera
     */
    public void doStopCamera() {

        try {
            if (null != mCamera) {
                mCamera.setPreviewCallback(null);
                mCamera.stopPreview();
            }
        } catch (Exception e) {
        }
    }

    public void initCamera() {
        if (mCamera != null) {
            try {
                mCamera.startPreview();
                Log.i(TAG, "init camera!!!!!!------");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 停止预览，释放Camera
     */
    public void doDestroyedCamera() {

        try {
            if (null != mCamera) {
                mCamera.setPreviewCallback(null);
                mCamera.stopPreview();
                mCamera.release();
                mCamera = null;
            }
        } catch (Exception e) {
        }
    }

    /**
     * 是否支持变焦
     *
     * @return isSuppport
     */
    public boolean isSupportZoom() {
        boolean isSuppport = true;
        try {
            if (mCamera.getParameters().isSmoothZoomSupported()) {
                isSuppport = false;
            }
        } catch (Exception e) {
            return true;
        }
        return isSuppport;
    }

    /**
     * 拍照
     */
    public void doTakePicture() throws Exception {
        mCamera.takePicture(mShutterCallback, null, mJpegPictureCallback);
    }

    /*为了实现拍照的快门声音及拍照保存照片需要下面三个回调变量*/
    Camera.ShutterCallback mShutterCallback = new Camera.ShutterCallback() {
        //快门按下的回调，在这里我们可以设置类似播放“咔嚓”声之类的操作。默认的就是咔嚓。
        public void onShutter() {
            if (tone == null)
                // 发出提示用户的声音
                tone = new ToneGenerator(
                        AudioManager.AUDIOFOCUS_REQUEST_GRANTED,
                        ToneGenerator.MIN_VOLUME);
            tone.startTone(ToneGenerator.TONE_PROP_BEEP);
        }
    };

    Camera.PictureCallback mRawCallback = new Camera.PictureCallback() {
        // 拍摄的未压缩原数据的回调,可以为null
        public void onPictureTaken(byte[] data, Camera camera) {
            // TODO Auto-generated method stub
            Log.i(TAG, "myRawCallback:onPictureTaken...");
        }
    };

    Camera.PictureCallback mJpegPictureCallback = new Camera.PictureCallback() {
        //对jpeg图像数据的回调,最重要的一个回调
        public void onPictureTaken(byte[] data, Camera camera) {
            // TODO Auto-generated method stub
            Log.i(TAG, "myJpegCallback:onPictureTaken...");
            Bitmap b = null;
            if (null != data) {
                b = BitmapFactory.decodeByteArray(data, 0, data.length);//data是字节数据，将其解析成位图
                mCamera.stopPreview();
//                isPreviewing = false;
            }
            //保存图片到sdcard
            if (null != b) {
                //设置FOCUS_MODE_CONTINUOUS_VIDEO)之后，myParam.set("rotation", 90)失效。
                //图片竟然不能旋转了，故这里要旋转下
                try {
                    Bitmap hBitmap = null;
                    if (TakePhoto.rotate > 90) {
                        hBitmap = b;
                    } else {
                        hBitmap = ImageUtil.rotaingImageView(90, b);
                    }
                    BitmapUtil.saveImageToGallery(mContext, hBitmap, TakePhoto.TEMP_PHONE_FILENAME);
                } catch (Exception e) {

                }
            }
            mCamera.startPreview();
        }

    };

    /**
     * 找出最适合的预览界面分辨率
     *
     * @param screenResolution
     * @param screenOrientation
     * @param cameraParameters
     * @param cameraOrientation
     * @return
     */
    public static Point findBestPreviewResolution(Camera.Parameters cameraParameters, Point screenResolution, int screenOrientation, int cameraOrientation) {
        Camera.Size defaultPreviewResolution = cameraParameters.getPreviewSize(); //默认的预览尺寸
        List<Camera.Size> rawSupportedSizes = cameraParameters.getSupportedPreviewSizes();
        if (rawSupportedSizes == null) {
            return new Point(defaultPreviewResolution.width, defaultPreviewResolution.height);
        }
        // 按照分辨率从大到小排序
        List<Camera.Size> supportedPreviewResolutions = new ArrayList<Camera.Size>(rawSupportedSizes);
        Collections.sort(supportedPreviewResolutions, new Comparator<Camera.Size>() {
            @Override
            public int compare(Camera.Size a, Camera.Size b) {
                int aPixels = a.height * a.width;
                int bPixels = b.height * b.width;
                if (bPixels < aPixels) {
                    return -1;
                }
                if (bPixels > aPixels) {
                    return 1;
                }
                return 0;
            }
        });

        // 在camera分辨率与屏幕分辨率宽高比不相等的情况下，找出差距最小的一组分辨率
        // 由于camera的分辨率是width>height，这里先判断我们的屏幕和相机的角度是不是相同的方向(横屏 or 竖屏),然后决定比较的时候要不要先交换宽高值
        final boolean isCandidatePortrait = screenOrientation % 180 != cameraOrientation % 180;
        final double screenAspectRatio = (double) screenResolution.x / (double) screenResolution.y;
        // 移除不符合条件的分辨率
        Iterator<Camera.Size> it = supportedPreviewResolutions.iterator();
        while (it.hasNext()) {
            Camera.Size supportedPreviewResolution = it.next();
            int width = supportedPreviewResolution.width;
            int height = supportedPreviewResolution.height;
            // 移除低于下限的分辨率，尽可能取高分辨率
            if (width * height < MIN_PREVIEW_PIXELS) {
                it.remove();
                continue;
            }
            //移除宽高比差异较大的
            int maybeFlippedWidth = isCandidatePortrait ? height : width;
            int maybeFlippedHeight = isCandidatePortrait ? width : height;
            double aspectRatio = (double) maybeFlippedWidth / (double) maybeFlippedHeight;
            double distortion = Math.abs(aspectRatio - screenAspectRatio);
            if (distortion > MAX_ASPECT_DISTORTION) {
                it.remove();
                continue;
            }
            // 找到与屏幕分辨率完全匹配的预览界面分辨率直接返回
            if (maybeFlippedWidth == screenResolution.x && maybeFlippedHeight == screenResolution.y) {
                Point exactPoint = new Point(width, height);
//                WeQrLogger.d(TAG, "found preview resolution exactly matching screen resolutions: " + exactPoint);
                return exactPoint;
            }
            //删掉宽高比比屏幕小的,防止左右出现白边
            if (aspectRatio - screenAspectRatio < 0) {
                it.remove();
                continue;
            }
        }
        // 如果没有找到合适的，并且还有候选的像素，则设置分辨率最大的
        if (!supportedPreviewResolutions.isEmpty()) {
            Camera.Size largestPreview = supportedPreviewResolutions.get(0);
            Point largestSize = new Point(largestPreview.width, largestPreview.height);
//            WeQrLogger.d(TAG, "using largest suitable preview resolution: " + largestSize);
            return largestSize;
        }
        //如果最后集合空了且本身支持640*480,则选择640*480
        if (supportedPreviewResolutions.isEmpty()) {
            it = rawSupportedSizes.iterator();
            while (it.hasNext()) {
                final Camera.Size next = it.next();
                if (next.width == 640 && next.height == 480) {
                    return new Point(next.width, next.height);
                }
            }
        }
        // 没有找到合适的，就返回默认的
        Point defaultResolution = new Point(defaultPreviewResolution.width, defaultPreviewResolution.height);
//        WeQrLogger.i(TAG, "No suitable preview resolutions, using default: " + defaultResolution);
        return defaultResolution;
    }

    /**
     * 相机预览显示在屏幕上的大小,默认是宽度充满屏幕,按比例缩放高度;如果此时高度超过屏幕高度,则再次缩放高度等于屏幕高度,这时宽度会小于屏幕宽度.
     * 坐标相对于displaySize, 可以直接应用于 LayoutParams,left 和 top 用 margin 即可.
     *
     * @param parentSize        屏幕尺寸或者限制尺寸
     * @param previewSize       相机预览尺寸
     * @param screenOrientation 屏幕方向(0,90,180,270)
     * @param cameraOrientation 相机方向(0,90,180,20)
     * @param centerHorizontal  如果为 FALSE 则默认左对齐
     * @param centerVertical    如果为 FALSE, 则默认顶端对齐
     * @return
     */
    public static Rect getSurfaceViewRect(Point parentSize, int screenOrientation, Point previewSize, int cameraOrientation, boolean centerHorizontal, boolean centerVertical) {
        Point previewSize2 = new Point();
        //方向不一致则交换
        if (screenOrientation % 180 != cameraOrientation % 180) {
            previewSize2.set(previewSize.y, previewSize.x);
        } else {
            previewSize2 = previewSize;
        }
        int width = parentSize.x;
        int height = previewSize2.y * width / previewSize2.x;
        if (height > parentSize.y) {
            width = width * parentSize.y / height;
            height = parentSize.y;
        }
        int left = 0;
        int top = 0;
        int right = width;
        int bottom = top + height;
        //这里算出来至少有一边是充满屏幕的
        if (width == parentSize.x) { //宽度充满
            if (centerVertical) {
                left = 0;
                top = (parentSize.y - height) / 2;
                right = width;
                bottom = top + height;
            }
        } else { //高度充满
            if (centerHorizontal) {
                left = (parentSize.x - width) / 2;
                top = 0;
                right = left + width;
                bottom = height;
            }
        }
        return new Rect(left, top, right, bottom);
    }

}
